#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include "TreeNode.h"
#include "TreeNodeExtern.h"

using namespace std;

static std::string getNodeKindName(NodeKind kind) {
    switch (kind) {
        case StmtK:
            return "StmtK";
        case ExpK:
            return "ExpK";
        default:
            return "Unknown NodeKind";
    }
}

static std::string getStmtKindName(StmtKind kind) {
    switch (kind) {
        case IfK:
            return "IfK";
        case RepeatK:
            return "RepeatK";
        case AssignK:
            return "AssignK";
        case ReadK:
            return "ReadK";
        case WriteK:
            return "WriteK";
        case Stmt_K:
            return "StmtNode";
        default:
            return "Unknown StmtKind";
    }
}

static std::string getExpKindName(ExpKind kind) {
    switch (kind) {
        case OpK:
            return "OpK";
        case ConstK:
            return "ConstK";
        case IdK:
            return "IdK";
        default:
            return "Unknown ExpKind";
    }
}

static std::string getExpTypeName(ExpType type) {
    switch (type) {
        case Void_type:
            return "Void_type";
        case Integer:
            return "Integer";
        case Boolean:
            return "Boolean";
        default:
            return "Unknown ExpType";
    }
}

static std::string Token_Kind_to_string(int token_kind) {
    switch (token_kind) {
        case ASSIGN:
            return ":=";
        case EQ:
            return "=";
        case LT:
            return "<";
        case PLUS:
            return "+";
        case MINUS:
            return "-";
        case TIMES:
            return "*";
        case OVER:
            return "/";
        case LPAREN:
            return "(";
        case RPAREN:
            return ")";
        case SEMI:
            return ";";
        case ERROR:
            return "ERROR";
        default:
            return "unknown token";
    }
}

void TreeNode::show_info(int depth,bool is_last_child){
        // 输出当前节点的信息
    for (int i = 0; i < depth; i++) {
        if (i == depth-1) {
            if (is_last_child) {
                cout << "└── ";
            } else {
                cout << "├── ";
            }
        } else {
            cout << "│   ";
        }
    }

    cout<<"line: "<<this->lineno<<", type: "<<getExpTypeName(type);
    cout<<", ";
    if(this->kind==StmtK){
        cout<<"stmt: "<<getStmtKindName(production_kind.stmt)<<endl;
    }else{
        cout<<"exp: "<<getExpKindName(production_kind.exp);
        switch (production_kind.exp)
        {
        case OpK:
            cout<<", op: "<<Token_Kind_to_string(attr.op)<<endl;
            break;
        case ConstK:
            cout<<", val: "<<attr.val<<endl;
            break;
        case IdK:
            cout<<", name: "<<attr.name<<endl;
            break;
        default:
            cout<<endl;
            break;
        }
    }
    
  // 递归输出子节点
    for (size_t i = 0; i < children.size(); i++) {
        if (children[i] != nullptr) {
            children[i]->show_info(depth + 1, (i == (children.size() - 1)));
        } else {
            if (i == children.size() - 1) {
                for (int j = 0; j < depth + 1; j++) {
                    if (j == depth) {
                        cout << "└── ";
                    } else {
                        cout << "│   ";
                    }
                }
            } else {
                for (int j = 0; j < depth + 1; j++) {
                    if (j == depth) {
                        cout << "├── ";
                    } else {
                        cout << "│   ";
                    }
                }
            }
        }
    }
};

void TreeNode::show_all_info(){
    show_info(0,false);
}

TreeNode *new_stmt_node(){
    TreeNode *stmt = new StmtNode(1);
    stmt->kind = StmtK;
    stmt->type = Void_type;
    stmt->production_kind.stmt=Stmt_K;
    return stmt;
};
TreeNode * new_if_stmt(int line,TreeNode * cond, TreeNode * then_stmt, TreeNode * else_stmt){
    TreeNode * if_stmt = new IfNode(line,cond, then_stmt, else_stmt);
    if_stmt->kind = StmtK;
    if_stmt->type = Void_type;
    if_stmt->production_kind.stmt=IfK;
    return if_stmt;
};
TreeNode * new_if_stmt(int line,TreeNode * cond, TreeNode * then_stmt){
    TreeNode * if_stmt = new IfNode(line,cond, then_stmt);
    if_stmt->kind = StmtK;
    if_stmt->type = Void_type;
    if_stmt->production_kind.stmt=IfK;
    return if_stmt;
};

TreeNode * new_repeat_stmt(int line,TreeNode * body,TreeNode * cond){
    TreeNode * repeat_stmt = new RepeatNode(line,body, cond);
    repeat_stmt->kind = StmtK;
    repeat_stmt->type = Void_type;
    repeat_stmt->production_kind.stmt=RepeatK;
    return repeat_stmt;
};

TreeNode * new_assign_stmt(int line,TreeNode * var, TreeNode * exp){
    TreeNode * assign_stmt = new AssignNode(line,var, exp);
    assign_stmt->kind = StmtK;
    assign_stmt->type = Void_type;
    assign_stmt->production_kind.stmt=AssignK;
    return assign_stmt;
};

TreeNode * new_read_stmt(int line,TreeNode * var){
    TreeNode * read_stmt = new ReadNode(line,var);
    read_stmt->kind = StmtK;
    read_stmt->type = Void_type;
    read_stmt->production_kind.stmt=ReadK;
    return read_stmt;
};

TreeNode * new_write_stmt(int line,TreeNode * exp){
    TreeNode * write_stmt = new WriteNode(line,exp);
    write_stmt->kind = StmtK;
    write_stmt->type = Void_type;
    write_stmt->production_kind.stmt=WriteK;
    return write_stmt;
};

TreeNode * new_exp(int line,TreeNode * left, Token_Kind op, TreeNode * right){
    TreeNode * exp = new ExpNode(line,left, right);
    exp->kind = ExpK;
    exp->type = Integer;
    exp->production_kind.exp=OpK;
    exp->attr.op = op;
    return exp;
};
TreeNode * new_exp(int line,TreeNode * simple_exp){
    TreeNode*exp =new ExpNode(line,simple_exp);
    exp->kind = ExpK;
    exp->type = Integer;
    exp->production_kind.exp=OpK;
    return exp;
};

TreeNode*new_exp(int line){
    TreeNode * exp = new ExpNode(line);
}

TreeNode * new_term(int line,TreeNode * left, Token_Kind op, TreeNode * right){
    TreeNode * term = new TermNode(line,left, right);
    term->kind = ExpK;
    term->type = Integer;
    term->production_kind.exp=OpK;
    term->attr.op = op;
    return term;
};
TreeNode * new_term(int line,TreeNode * factor){
    TreeNode*term =new TermNode(line,factor);
    term->kind = ExpK;
    term->type = Integer;
    term->production_kind.exp=OpK;
    return term;
};

TreeNode* new_simple_exp(int line,TreeNode * left, Token_Kind op, TreeNode * right){
    TreeNode * simple_exp = new SimpleExpNode(line,left, right, op);
    return simple_exp;
};

TreeNode * new_num(int line,int val){
    TreeNode * num = new NumNode(line,val);
    return num;
};
TreeNode * new_id(int line,const char *name){
    TreeNode * id = new IdNode(line,name);
    return id;
};
